package com.um.springboot.starter.interceptors;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import com.um.springboot.starter.annotation.TokenRequired;
import com.um.springboot.starter.code.CommonCode;
import com.um.springboot.starter.orm.entity.Response;
import com.um.springboot.starter.properties.HshProperties;
import com.um.springboot.starter.service.CommonService;
import com.um.springboot.starter.utils.StringUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Date;
import java.util.Map;


/**
 * Created by renjunwei on 2020/9/17
 */
@Aspect
@Component
@Order(value = AspectOrders.LOGIN_ORDER)
public class TokenRequiredInterceptor {

    @Resource
    private HttpServletRequest request;

    @Autowired
    private CommonService commonService;

    @Autowired
    private HshProperties hshProperties;

    @Autowired
    private RedisTemplate redisTemplate;


    //@Around注解 环绕执行，就是在调用之前和调用之后，都会执行一定的逻辑
    @Around("execution(* com.um..controller.*.*(..)) || execution(* com.hsh..controller.*.*(..))")
    public Object doAround(ProceedingJoinPoint pjp) throws Throwable {

        //获取方法注解
        MethodSignature signature = (MethodSignature) pjp.getSignature();
        TokenRequired loginTokenRequired = signature.getMethod().getAnnotation(TokenRequired.class);

        //获取类注解
        if(loginTokenRequired == null){
            loginTokenRequired = pjp.getTarget().getClass().getAnnotation(TokenRequired.class);
        }

        //校验
        if(loginTokenRequired != null && loginTokenRequired.required()) {

            String tokenStr = StringUtil.getTrim(request.getHeader(hshProperties.getToken().getKey()));
            if(tokenStr.equals("")){
                return Response.failed(CommonCode.LoginExpired);
            }

            if("redis".equals(hshProperties.getToken().getType())){
                Object redisToken = redisTemplate.opsForValue().get(tokenStr);
                if(null == redisToken){
                    return Response.failed(CommonCode.LoginExpired);
                }
            } else if ("sa-token".equals(hshProperties.getConfig().getSessionType())) {
                StpUtil.checkLogin();
            }else{

                Map tokenMap = commonService.queryEntity(hshProperties.getToken().getTableName(), hshProperties.getToken().getKey(), tokenStr);
                if(null == tokenMap){
                    return Response.failed(CommonCode.LoginExpired);
                }
                String  userId = StringUtil.getTrim(tokenMap.get(hshProperties.getToken().getUserField()));
                Long expire = hshProperties.getToken().getExpire();
                if(expire > 0){
                    long createDateTime;

                    Object createTime = tokenMap.get("create_time");
                    if(createTime instanceof LocalDateTime){
                        createDateTime = ((LocalDateTime)tokenMap.get("create_time")).atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
                    }else{
                        createDateTime = ((Date)tokenMap.get("create_time")).getTime();
                    }

                    long between = DateUtil.between(new Date(), new Date(createDateTime), DateUnit.MINUTE);
                    if (between > expire) {
                        return Response.failed(CommonCode.LoginExpired);
                    }
                }

                if(hshProperties.getToken().isCheckUserStatus()){//是否验证用户状态
                    Map userMap = commonService.queryEntity(hshProperties.getToken().getUserTableName(),hshProperties.getToken().getUserField(),userId);
                    if(userMap != null){
                        String status = StringUtil.getTrim(userMap.get(hshProperties.getToken().getUserStatusField()));
                        if(!status.equals(hshProperties.getToken().getUserStatus())){//停用状态
                            return Response.failed(CommonCode.AccountDisabled);
                        }
                    }
                }

            }


        }

        return pjp.proceed();
    }

}
